package com.be.beadmin.basicData.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.be.beadmin.basicData.dto.input.UserDto;
import com.be.beadmin.basicData.dto.input.UserOrgFilter;
import com.be.beadmin.basicData.dto.input.UserRolesDto;
import com.be.beadmin.basicData.dto.output.UserEx;
import com.be.beadmin.basicData.dto.output.UserNameId;
import com.be.beadmin.basicData.entity.*;
import com.be.beadmin.basicData.mapper.UserMapper;
import com.be.beadmin.basicData.repository.OrganizationRepository;
import com.be.beadmin.basicData.repository.RoleRepository;
import com.be.beadmin.basicData.repository.UserRepository;
import com.be.beadmin.basicData.service.UserService;
import com.be.beadmin.common.entity.*;
import com.be.beadmin.common.exception.BeadminException;

import com.be.beadmin.common.impl.UserCacheManager;
import com.be.beadmin.common.utils.JpaQueryBuilder;
import com.be.beadmin.common.utils.JpaSortBuilder;
import com.be.beadmin.common.utils.JwtUtil;
import com.be.beadmin.service.constant.UserConst;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {


    public String TRAN_KEY = "key";
    public String TRAN_TITLE = "title";
    public String TRAN_DISABLED = "disabled";
    public String TRAN_CHECKED = "checked";
    public String TRAN_DATA = "data";
    public String TRAN_VALUE = "value";


    @Autowired
    UserRepository userRepository;


    @Autowired
    RoleRepository roleRepository;

    @Autowired
    UserMapper userMapper;



    @Autowired
    UserCacheManager userCacheManager;


    @Autowired
    OrganizationRepository organizationRepository;

    @Override
    public UserEx viewBaseInfo(HttpServletRequest request) {

        //        HttpSession session = request.getSession();
//        String username = (String) session.getAttribute("username");
        String token = request.getHeader("Authentication");
        String userid ="";
        try{

            Claims claims = JwtUtil.parseJWT(token);
            userid = claims.getSubject();
            User user = userRepository.findUserByIdAndDelete(userid,0);
            UserEx userEx = userMapper.toEntity(user);
            List<String> roles = user.getRoles().stream().map(item -> item.getCode()).collect(Collectors.toList());;
//            Set<Role> roleList = ;
//            if(roleList != null && roleList.size() > 0) {
//                roles =
//            }
//            // 获取menus
            Set<Role> roleList = user.getRoles();
            List<Menu> menuList = new ArrayList<>();
            for (Role role : roleList) {
                for(Menu menu : role.getMenus()){
                    if(!menuList.contains(menu)){
                        menuList.add(menu);
                    }
                }
            }


            List<String> menus =menuList.stream().
                    map(item -> item.getCode()).distinct().collect(Collectors.toList());

            userEx.setPermissionInfos(menus);


            userEx.setRoleInfos(roles);
//            SimpleUserBo simpleUserBo = new SimpleUserBo(user);
//            if(employee!=null){
//                return new JsonResult(new SimpleUserInfoBo(employee));
//            }else{
            return userEx;
//            }
        }catch (Exception e){
             throw new BeadminException("解析报错");
        }

    }

    /**
     * 获取当前用户的所有角色
     *
     * @param request
     * @return
     */
    @Override
    public Set<Role> getRolesByCurrentUser(HttpServletRequest request) {
        UserEx userEx = viewBaseInfo(request);
        User user = userRepository.findUserByIdAndDelete(userEx.getId(), 0);
        Set<Role> roleList = user.getRoles();
        return roleList;
    }

    /**
     * 获取某个用户的角色
     *
     * @param user
     * @return
     */
    @Override
    public Set<Role> getRolesByUser(User user) {


        return null;
    }

    /**
     * 获取某个角色的所有用户
     *
     * @param role
     * @return
     */
    @Override
    public List<User> getUserByRole(Role role) {
        return null;
    }

    @Override
    public Page<UserEx> getUserByPage(UserOrgFilter pageEntity) {


        Pageable pageable = PageRequest.of(
                pageEntity.getCurrent() -1,
                pageEntity.getPageSize());
//        UserQueryCriteria criteria = new UserQueryCriteria();
//        criteria.setName("cw");
        Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> list = new ArrayList<>();
                    Predicate pre1 =   JpaQueryBuilder.getPredicate(root, pageEntity.getFilters(), criteriaBuilder);
                    list.add(pre1);
                    Predicate pre2 = criteriaBuilder.equal(root.get(User_.delete), 0); //过滤为0
                    list.add(pre2);

                    if (!StringUtils.isEmpty(pageEntity.getOrgId())) {
                        // 级联查询
                        Predicate pre3 = criteriaBuilder.equal(root.get(User_.organization)
                                .get(Organization_.id), pageEntity.getOrgId()); //过滤为0
                        list.add(pre3);
                    }
                    if (null != pageEntity.getRoleIds() && pageEntity.getRoleIds().size() > 0) {
                        Join<User,Role> join = root.join(User_.roles, JoinType.LEFT);
                        list.add(criteriaBuilder.in(join.get("id")).value(pageEntity.getRoleIds()));
                    }

                    Predicate[] p = new Predicate[list.size()];

                    List<Order> orders = new ArrayList<>();
                    if(pageEntity.getSorters() != null && pageEntity.getSorters().size() > 0) {
                        orders = JpaSortBuilder.getPredicate(root, pageEntity.getSorters(), criteriaBuilder);
                        criteriaQuery.orderBy(orders);
                    } else {
                        criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Role_.createTime).as(Date.class)));
                    }
                    return  criteriaBuilder.and(list.toArray(p));
                }
                , pageable);
        Page<UserEx> page1 = page.map(item -> {
            UserEx userEx = userMapper.toEntity(item);

            if(ObjectUtil.isNotEmpty(item.getOrganization())) {
                userEx.setOrgId(item.getOrganization().getId());
            }
            if(ObjectUtil.isNotEmpty(item.getRoles()) && item.getRoles().size() > 0) {
                List<String> roleIds = item.getRoles()
                        .stream().map(item1 -> item1.getId()).collect(Collectors.toList());
                userEx.setRoleIds(roleIds);
            }
//            if (!ObjectUtil.isEmpty(item.getCustomer())) {
//                userEx.setCustomerName(item.getCustomer().getName());
//                userEx.setCustomerId(item.getCustomer().getId());
//            }
////
            return userEx;});

        return page1;

    }

    @Override
    public void addUser(UserDto userDto) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = "";
        if (StringUtils.isEmpty(userDto.getPassword())) {
            // 添加默认编码
            password = passwordEncoder.encode("123456");
        } else {
            password = passwordEncoder.encode(userDto.getPassword());
        }
        User hasUser = userRepository.findUserByNameAndDelete(userDto.getName(), 0);
        if (ObjectUtil.isNotEmpty(hasUser)) {
            throw new BeadminException("该用户已经存在切勿重复添加");
        }
        User user = new User();
        user.setPassword(password);
        user.setName(userDto.getName());
        if(ObjectUtil.isNotEmpty(userDto.getOrgId())) {
            Organization organization = organizationRepository.findOrganizationByIdAndDelete(userDto.getOrgId(), 0);
            user.setOrganization(organization);
        }

        if(userDto.getRoleIds() != null && userDto.getRoleIds().size() > 0) {
            Set<Role> roles = roleRepository.findRolesByDeleteAndIdIn(0 , userDto.getRoleIds());
            user.setRoles(roles);
        }
        user.setEmail(userDto.getEmail() != null? userDto.getEmail(): user.getEmail());
        user.setGender(userDto.getGender() != null? userDto.getGender(): user.getGender());
        user.setPhone(userDto.getPhone() != null? userDto.getPhone(): user.getPhone());
        user.setAvatarName(userDto.getAvatarName() != null? userDto.getAvatarName(): user.getAvatarName());
        user.setAvatarPath(userDto.getAvatarPath() != null? userDto.getAvatarPath(): user.getAvatarPath());
        userRepository.save(user);
    }

    @Override
    @CacheEvict(value = "users",key = "#userDto.id")
    public void updatePassword(UserDto userDto) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = "";
        if (StringUtils.isEmpty(userDto.getPassword())) {
            // 添加默认编码
            password = passwordEncoder.encode("123456");
        } else {
            password = passwordEncoder.encode(userDto.getPassword());
        }
        User user = userRepository.findUserByIdAndDelete(userDto.getId(),0);
        user.setPassword(password);
        userRepository.save(user);
    }

    @Override
    @CacheEvict(value = "users",key = "#userDto.id")
    public void updateUser(UserDto userDto) {

        User user = userRepository.findUserByIdAndDelete(userDto.getId(),0);
        if(ObjectUtil.isNotEmpty(userDto.getOrgId())) {
            Organization organization = organizationRepository.findOrganizationByIdAndDelete(userDto.getOrgId(), 0);
            user.setOrganization(organization);
        }

        if(userDto.getRoleIds() != null && userDto.getRoleIds().size() > 0) {
            Set<Role> roles = roleRepository.findRolesByDeleteAndIdIn(0 , userDto.getRoleIds());
            user.setRoles(roles);
        }
        user.setEmail(userDto.getEmail() != null? userDto.getEmail(): user.getEmail());
        user.setGender(userDto.getGender() != null? userDto.getGender(): user.getGender());
        user.setPhone(userDto.getPhone() != null? userDto.getPhone(): user.getPhone());
        user.setAvatarName(userDto.getAvatarName() != null? userDto.getAvatarName(): user.getAvatarName());
        user.setAvatarPath(userDto.getAvatarPath() != null? userDto.getAvatarPath(): user.getAvatarPath());
        userRepository.save(user);

    }

    @Override
    @CacheEvict(value = "users",key = "#userDto.id")
    public void delUser(UserDto userDto) {
        User user = userRepository.findUserByIdAndDelete(userDto.getId(),0);
        if(user.getSystem()) {
            throw new BeadminException("该用户是系统用户无法删除");
        }
        user.setDelete(1);
        userRepository.save(user);
    }

    //todo:暂时不做
    @Override
    public void delUsers(List<UserDto> userDtoList) {

    }

    @Override
    public void lockUser(UserDto userDto) {
        User user = userRepository.findUserByIdAndDelete(userDto.getId(),0);
        if(user.getSystem()) {
            throw new BeadminException("该用户是系统用户无法锁定");
        }
        user.setLocked(true);
        userRepository.save(user);
    }

    @Override
    @CacheEvict(value = "users",key = "#userRolesDto.userId")
    public void saveRoles(UserRolesDto userRolesDto) {
        User user = userRepository.findUserByIdAndDelete(userRolesDto.getUserId(),0);
        Set<Role> roles = roleRepository.findRolesByDeleteAndIdIn(0 , userRolesDto.getRolesId());
        user.setRoles(roles);
        userRepository.save(user);
    }

    @Override
    public Map<String, Object> ajaxLoadTransferUserRelRole(String userid) {

        Map<String, Object> result = new HashMap<String, Object>();
        User user = userRepository.findUserByIdAndDelete(userid,0);
        Set<Role> roleExist = user.getRoles();
        List<Role> roleAll = roleRepository.findRolesByDelete(0);
        //data值
        JSONArray arr = new JSONArray();
        for(Role r : roleAll){
            JSONObject o = new JSONObject();
            o.put(TRAN_KEY,r.getId());
            o.put(TRAN_TITLE,r.getName());
            o.put(TRAN_DISABLED,"");
            o.put(TRAN_CHECKED,"");
            arr.add(o);
        }
        result.put(TRAN_DATA,arr);
        //value值
        List<String> listids = new ArrayList<String>();
        for(Role r : roleExist){
            listids.add(r.getId());
        }
        result.put(TRAN_VALUE,listids);
        return result;

    }

    @Override
    public String reLogin(String userName) {
        // 根据userName获取Id
        User user = userRepository.findUserByNameAndDelete(userName, 0);
        String id = user.getId();
        String token = JwtUtil.createJWT(id);
        userCacheManager.updateToken(id,token, true,new Date());
        return token;
    }

    /**
     * 是当前用户否为某个角色
     *
     * @param request
     * @param roleCode
     * @return
     */
    @Override
    public boolean isRole(HttpServletRequest request, String roleCode) {
        boolean flag = false;
        for (Role role : getRolesByCurrentUser(request)) {
            if (role.getCode().equals(roleCode)) {
                flag = true;
            }
        }
        return flag;
    }


    /**
     * 是当前用户否为某个角色
     * @param user
     * @param roleName
     * @return
     */
    @Override
    public boolean isRole(User user, String roleName) {

        boolean flag = false;
        for (Role role : user.getRoles()) {
            if (role.getName().equals(roleName)) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 是当前用户否为admin系统管理员
     *
     * @param request
     * @return
     */
    @Override
    public boolean isAdmin(HttpServletRequest request) {

        return isRole(request, UserConst.ADMINROLECODE);
    }

    @Transactional
    public User getUser(String name) {
        User user = userRepository.findUserByNameAndDelete(name, 0);
        if(ObjectUtil.isEmpty(user)) {
            throw new BeadminException("该账户不存在");
        }
        Set<Role> roles = user.getRoles();
        System.out.println(roles.size());
        return user;
    }

    /**
     * 根据角色类型获取该角色的所有用户
     *
     * @param roleName
     * @return
     */
    @Override
    public List<User> getUserByRoleType(String roleName) {
        List<User> userList = new ArrayList<>();
        for (User user : userRepository.findAll()) {
            for (Role role : user.getRoles()) {
                if (role.getName().equals(roleName)) {
                    userList.add(user);
                    break;
                }
            }
        }

        return userList;
    }

    /**
     * 根据id获取用户
     *
     * @param id
     * @return
     */
    @Override
    public User getUserById(String id) {
        User userByIdAndDelete = userRepository.findUserByIdAndDelete(id, 0);
        return userByIdAndDelete;
    }

    @Override
    public List<UserNameId> getUserNameAndIdByRoleType(String roleName) {
        List<UserNameId> userList = new ArrayList<>();
        for (User user : userRepository.findUsersByDelete(0)) {
            for (Role role : user.getRoles()) {
                if (role.getName().equals(roleName)) {
                    userList.add(new UserNameId(user.getId(),user.getName()));
                    break;
                }
            }
        }

        return userList;
    }

    /**
     * 获取所有用户id和用户名
     *
     * @return
     */
    @Override
    public List<UserNameId> getAllUserNameAndId() {
        return userRepository.findAllUser();
    }
}
